﻿Imports System.Windows.Forms.Design
Imports System.ComponentModel.Design
Imports System.ComponentModel
Imports System.Runtime.InteropServices

Public Class cTabControlDesigner
    Inherits System.Windows.Forms.Design.ParentControlDesigner

    Private m_verbs As DesignerVerbCollection = New DesignerVerbCollection
    Private m_DesignerHost As IDesignerHost
    Private m_SelectionService As ISelectionService

    Public Sub New()
        MyBase.New()

        Dim verb1 As New DesignerVerb("Add Tab", AddressOf OnAddPage)
        Dim verb2 As New DesignerVerb("Insert Tab", AddressOf OnInsertPage)
        Dim verb3 As New DesignerVerb("Remove Tab", AddressOf OnRemovePage)
        m_verbs.AddRange(New DesignerVerb() {verb1, verb2, verb3})

    End Sub

    Public Overrides ReadOnly Property Verbs() As System.ComponentModel.Design.DesignerVerbCollection
        Get
            If m_verbs.Count = 3 Then
                Dim MyControl As cTabControl = CType(Me.Control, cTabControl)
                If MyControl.TabCount > 0 Then
                    m_verbs(1).Enabled = True
                    m_verbs(2).Enabled = True
                Else
                    m_verbs(1).Enabled = False
                    m_verbs(2).Enabled = False
                End If
            End If
            Return m_verbs
        End Get
    End Property

    Public ReadOnly Property DesignerHost() As IDesignerHost
        Get
            If m_DesignerHost Is Nothing Then
                m_DesignerHost = DirectCast(GetService(GetType(IDesignerHost)), IDesignerHost)
            End If
            Return m_DesignerHost
        End Get
    End Property

    Public ReadOnly Property SelectionService() As ISelectionService
        Get
            If m_SelectionService Is Nothing Then
                m_SelectionService = DirectCast(GetService(GetType(ISelectionService)), ISelectionService)
            End If
            Return m_SelectionService
        End Get
    End Property

    Sub OnAddPage(ByVal sender As Object, ByVal e As EventArgs)

        Dim ParentControl As cTabControl = DirectCast(Control, cTabControl)
        Dim oldTabs As Control.ControlCollection = ParentControl.Controls

        RaiseComponentChanging(TypeDescriptor.GetProperties(ParentControl)("TabPages"))

        Dim P As cTabPage = DirectCast(DesignerHost.CreateComponent(GetType(cTabPage)), cTabPage)
        P.Text = P.Name
        ParentControl.TabPages.Add(P)

        RaiseComponentChanged(TypeDescriptor.GetProperties(ParentControl)("TabPages"), oldTabs, ParentControl.TabPages)
        ParentControl.SelectedTab = P

        SetVerbs()

    End Sub

    Sub OnInsertPage(ByVal sender As Object, ByVal e As EventArgs)

        Dim ParentControl As cTabControl = DirectCast(Control, cTabControl)
        Dim oldTabs As Control.ControlCollection = ParentControl.Controls
        Dim Index As Integer = ParentControl.SelectedIndex

        RaiseComponentChanging(TypeDescriptor.GetProperties(ParentControl)("TabPages"))

        Dim P As cTabPage = DirectCast(DesignerHost.CreateComponent(GetType(cTabPage)), cTabPage)
        P.Text = P.Name

        Dim tpc(ParentControl.TabCount) As TabPage
        'Starting at our Insert Position, store and remove all the tabpages.
        For i As Integer = Index To ParentControl.TabCount - 1
            tpc(i) = ParentControl.TabPages(Index)
            ParentControl.TabPages.Remove(ParentControl.TabPages(Index))
        Next
        'add the tabpage to be inserted.
        ParentControl.TabPages.Add(P)
        'then re-add the original tabpages.
        For i As Integer = Index To UBound(tpc) - 1
            ParentControl.TabPages.Add(tpc(i))
        Next

        RaiseComponentChanged(TypeDescriptor.GetProperties(ParentControl)("TabPages"), oldTabs, ParentControl.TabPages)
        ParentControl.SelectedTab = P

        SetVerbs()

    End Sub

    Sub OnRemovePage(ByVal sender As Object, ByVal e As EventArgs)

        Dim ParentControl As cTabControl = DirectCast(Control, cTabControl)
        Dim oldTabs As Control.ControlCollection = ParentControl.Controls

        If ParentControl.SelectedIndex < 0 Then Return

        RaiseComponentChanging(TypeDescriptor.GetProperties(ParentControl)("TabPages"))

        DesignerHost.DestroyComponent(ParentControl.TabPages(ParentControl.SelectedIndex))

        RaiseComponentChanged(TypeDescriptor.GetProperties(ParentControl)("TabPages"), oldTabs, ParentControl.TabPages)

        SelectionService.SetSelectedComponents(New IComponent() {ParentControl}, SelectionTypes.Auto)

        SetVerbs()

    End Sub

    Private Sub SetVerbs()

        Dim ParentControl As cTabControl = DirectCast(Control, cTabControl)

        Select Case ParentControl.TabPages.Count
            Case 0
                Verbs(1).Enabled = False
                Verbs(2).Enabled = False
            Case 1
                Verbs(1).Enabled = False
                Verbs(2).Enabled = True
            Case Else
                Verbs(1).Enabled = True
                Verbs(2).Enabled = True
        End Select

    End Sub

    Private Const WM_NCHITTEST As Integer = &H84

    Private Const HTTRANSPARENT As Integer = -1
    Private Const HTCLIENT As Integer = 1

    Protected Overrides Sub WndProc(ByRef m As Message)
        MyBase.WndProc(m)
        If m.Msg = WM_NCHITTEST Then
            'select tabcontrol when Tabcontrol clicked outside of TabItem.
            If m.Result.ToInt32 = HTTRANSPARENT Then
                m.Result = IntPtr.op_Explicit(HTCLIENT)
            End If
        End If

    End Sub

    Private Enum TabControlHitTest
        TCHT_NOWHERE = 1
        TCHT_ONITEMICON = 2
        TCHT_ONITEMLABEL = 4
        TCHT_ONITEM = TCHT_ONITEMICON Or TCHT_ONITEMLABEL
    End Enum

    Private Const TCM_HITTEST As Int32 = &H130D

    Private Structure TCHITTESTINFO
        Public pt As Point
        Public flags As TabControlHitTest
    End Structure

    Protected Overrides Function GetHitTest(ByVal point As System.Drawing.Point) As Boolean

        If (Me.SelectionService.PrimarySelection Is Me.Control) Then
            Dim hti As New TCHITTESTINFO

            hti.pt = Me.Control.PointToClient(point)

            Dim m As New Message
            m.HWnd = Me.Control.Handle
            m.Msg = TCM_HITTEST

            Dim lparam As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(hti))
            Marshal.StructureToPtr(hti, lparam, False)
            m.LParam = lparam

            MyBase.WndProc(m)
            Marshal.FreeHGlobal(lparam)

            If m.Result.ToInt32 <> -1 Then
                Return hti.flags <> TabControlHitTest.TCHT_NOWHERE
            End If

        End If

        Return False

    End Function


    Protected Overrides Sub OnPaintAdornments(ByVal pe As System.Windows.Forms.PaintEventArgs)
        'Don't want DrawGrid dots.
    End Sub

    'Fix the AllSizable selectiorule on DockStyle.Fill
    Public Overrides ReadOnly Property SelectionRules() As System.Windows.Forms.Design.SelectionRules
        Get
            If Me.Control.Dock = DockStyle.Fill Then
                Return System.Windows.Forms.Design.SelectionRules.Visible
            End If
            Return MyBase.SelectionRules
        End Get
    End Property

End Class
